package za.org.jcicada.nodeproxy.impl;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import za.org.jcicada.cfgmngr.SystemSetType;
import za.org.jcicada.confss.impl.ConfSS;
import za.org.jcicada.genss.ServiceURN;
import za.org.jcicada.genss.SystemURN;
import za.org.jcicada.genss.lifecycle.ILifeCycleServer.Shutdown;
import za.org.jcicada.genss.messages.Result;
import za.org.jcicada.genss.sensor.SensorURN;
import za.org.jcicada.genss.sensor.impl.Sensor;
import za.org.jcicada.watchdog.SystemWatchdog;

/**
 * Class used to manage a processing node. It monitors the status of the node
 * itself as well as managing the processes running on the node.
 * @author rcrida
 */
public class NodeProxy extends ConfSS {

    /** Logger object used for logging messages. */
    private static final Log logger = LogFactory.getLog(NodeProxy.class);

    /** Map of system URNs to client objects. */
    protected Map<SystemURN, NodeSystem> systemMap = new HashMap<SystemURN, NodeSystem>();
    
    /** Dynamic configuration object for this class, contents from CfgMngr. */
    private NodeProxyDynamicConfiguration nodeProxyDynamic = new NodeProxyDynamicConfiguration();

	/** Map of systems to watch and the corresponding objects */
	protected Map<SystemURN, SystemWatchdog> systemWatchdogs = new HashMap<SystemURN, SystemWatchdog>();
	
	/** Object used to monitor resource usage of this node. */
	private ResourceUsage resourceUsage = new ResourceUsage();

    /**
     * Constructor
     * @param systemURN the name of this device proxy object
     * @param uriCfgMngrLocation the location of the CfgMngr
     */
    public NodeProxy(SystemURN systemURN, URI uriCfgMngrLocation) throws URISyntaxException {
        super(systemURN, uriCfgMngrLocation);
    }
    
	/**
	 * Do base class initialization then create and start a ping timer.
	 */
	@Override
	protected void duringInitialize() throws Exception {
		super.duringInitialize();
		systemMap.clear();
		systemWatchdogs.clear();
	}

	/**
	 * Shutdown first stops the ping timer, sets all the watchdog sensors to
	 * UNKNOWN then stops the ConfSS base object.
	 */
	@Override
	protected void duringShutdown() throws Exception {
		for (NodeSystem nodeSystem : systemMap.values()) {
			nodeSystem.shutdown(Shutdown.HALT);
		}
		for (SystemWatchdog watchdog : systemWatchdogs.values()) {
			watchdog.shutdown();
		}
		resourceUsage.shutdown();
		super.duringShutdown();
	}

    @Override
    public void replyGetConfiguration(Result result, Object configuration) {
        if (systemMap.size() == 0) {
            super.replyGetConfiguration(result, configuration);
            nodeProxyDynamic.loadProperties((Properties) configuration);
            // and then start monitoring resource usage
            resourceUsage.initialize(getTimer(), nodeProxyDynamic.resourcePeriod_ms);
            resourceUsage.configure(nodeProxyDynamic);
            internalSetupSystems(nodeProxyDynamic.systemURNClassMap);
        }
        else {
            logger.error("Received configuration when already configured");
        }
    }

	public void replyLocateService(Result result, ServiceURN serviceURN, URI locationURI) {
	}

	public void replySensorSet(Result result, SystemURN systemURN, Set<SensorURN> sensorURNs) {
	}

	public void replySystemSet(Result result, SystemSetType type, Set<SystemURN> systemURNs) {
	}

    /**
     * Configure the .
     * @param urns semicolon separated list of system URNs
     */
    protected void internalSetupSystems(String systemURNs) {
        for (String urnClass : systemURNs.split(";")) {
			try {
	        	String[] args = urnClass.split("=");
	        	SystemURN systemURN = new SystemURN(args[0]);
	        	String className = args[1];
	        	NodeSystem system = new NodeSystem(className, systemURN, getCfgMngrLocation());
	        	system.initialize();
	            systemMap.put(systemURN, system);
	            // tell life cycle server about new system so that it can forward requests
	            lifeCycleServer.addSystem(systemURN, system);
	            // configure a watchdog for this system
				SystemWatchdog systemWatchdog = new SystemWatchdog(getConfigurationServer(), systemURN, getTimer(), nodeProxyDynamic.pingPeriod_ms, nodeProxyDynamic.pingTimeout_ms, nodeProxyDynamic.watchdogStatusStrategy);
				systemWatchdog.systemRegistered();
				systemWatchdogs.put(systemURN, systemWatchdog);
				addSensor(systemURN, systemWatchdog.getSensor());
			} catch (Exception ex) {
				logger.error(String.format("Error starting system %s", urnClass), ex);
			}
		}
    }
    
    @Override
    protected void addSensors() throws URISyntaxException {
    	super.addSensors();
        for (Sensor sensor : resourceUsage.getSensors()) {
            addSensor(getSystemURN(), sensor);
        }

    }
    
	/**
	 * Main function takes no arguments. A cfgmngr knows what it subsystemURI
	 * will be since there can be only one!
	 * 
	 * @param args
	 *            the command line arguments
	 */
	public static void main(String args[]) {
		String[] confssArgs = { NodeProxy.class.getCanonicalName(), args[0], args[1] };
		ConfSS.main(confssArgs);
	}

}
